This page last changed on Oct 04, 2007 by imoncada.

This page explains how to create a script in the OTrunk environment. I will use a javascript for this example, although you can write script in other languages like JRuby.

In general, the idea is that you set up the UI components in an otml file. Then, you can add script objects to the otml as well. These script objects are useful to control the user interface experience and to add interactivity, feedback, logging, etc.
The script objects are OTObjects as well, so they have to be added somewhere in the otml file in order to be loaded. The general rule would be that you add them in the same container where the objects that you want to control are located.
One script object can have access to more than one OTObject in your otml page.
You can have multiple script objects in an otml file, even next to each other in the same container, and mixed with other OTObjects. The order in which the scripts will be loaded might not be deterministic.
When you write a script, you can either write it directly in the otml file, or you can write it in a separate file and then reference it from the otml file. The first option is what we call an "embedded" script, but is mostly used only for quick testing. The latter option is recommended because that way you can keep your UI and you logic separate, and also, it might be easier to edit a script in a separate page, using an editor of your choice.

In this example, I'm going to create a script that writes something in the screen into an OTText object. It's a really simple and probably not very useful but my goal is to illustrate the steps to take.

Writing a new otml file with the visual components

Lay out your visual components in your otml file either manually or using some authoring tool. Just think about the UI without the script first. In this example, I'm going to use the following otml:

<?xml version="1.0" encoding="UTF-8"?>
<otrunk id="0f1473c0-7200-11dc-8314-0800200c9a66">

  <imports>
    <import class="org.concord.otrunk.OTSystem"/>
    <import class="org.concord.otrunk.view.OTViewBundle"/>
    <import class="org.concord.otrunk.view.OTViewEntry"/>
    <import class="org.concord.otrunk.view.document.OTCompoundDoc"/>
    <import class="org.concord.otrunk.ui.OTText"/>    
  </imports>

  <objects>
    <OTSystem>
      <bundles>
        <OTViewBundle showLeftPanel="false">
          <views>
            <OTViewEntry
              objectClass="org.concord.otrunk.ui.OTText" 
              viewClass="org.concord.otrunk.ui.swing.OTTextView"/>
            <OTViewEntry
              objectClass="org.concord.otrunk.view.document.OTDocument"
              viewClass="org.concord.otrunk.view.document.OTDocumentView" />
          </views>
        </OTViewBundle>
      </bundles>
      
      <root>
        <OTCompoundDoc>
        	<bodyText>
        		This is a document. The following text will be changed by a script:<br/>
        		<object refid="${text_object}"/>
        	</bodyText>
        </OTCompoundDoc>
      </root>

      <library>
      	<OTText local_id="text_object"/>
      </library>
      
    </OTSystem>
  </objects>
</otrunk>

The otml above just has a document as the root. The document has some text and it's also pointing to an OTText object with an id "text_object".
The script will manipulate this text_object and it will change its text inside (which is currently empty).

Adding a new empty OTScriptObject to the otml

Now, you can add a new OT script object to your otml. Since I like using the library, I'm going to add it to the library section. For now, I'll keep the script embedded in the otml file, to make the example simple.
My new OT script object will be something like this:

<OTScriptObject local_id="script_object">
  <script>
    <OTJavascript>
      <script>
      //Here is where I will write my script
      </script>
    </OTJavascript>
  </script>
</OTScriptObject>

The snippet above is to be added to the library section of the otml file.

Now, since I want my script to have access to my OTText object, I need to "pass" the object to it.
In order for your script to have access to OT objects defined in the otml file, you need to use the "variables" property of the OTScriptObject.
This is how it works for my example:

<OTScriptObject local_id="script_object">
  <variables>
    <OTScriptVariable name="myTextVariable" reference="${text_object}"/>
  </variables>
  <script>
    <OTJavascript>
      <script>
      //Here is where I will write my script
      </script>
    </OTJavascript>
  </script>
</OTScriptObject>

Now the script will have access to the object defined with an id of "text_object" in the otml, and within the script I can refer to it simply as "myTextVariable".

Adding the script to a container so it can be run

So far, the script object is defined, but if we run the otml file, it will not be loaded or run. That is because the root object on the otml file is a document, so the OTViewer will just display the document and that's it. It doesn't care about the rest of the otml file contents unless it needs to display it.
In this case, since we have a compound document in our root, and it is itself a container, we can add the script to the document directly. In a compound document, you can add other objects by adding a reference to them into the "bodyText" property, just like we added the OTText object to the document.
So, we have to edit the otml file adding the script object, with its local_id, which is "script_object":

<OTCompoundDoc>
  <bodyText>
    This is a document. The following text will be changed by a script:<br/>
    <object refid="${text_object}"/>
    <object refid="${script_object}"/>
  </bodyText>
</OTCompoundDoc>

Ok, now the script will be loaded because it is part of the root document.
We still need an extra step. When the OTViewer tries to load the OTScript object, it will look for a "view" to display in the screen next to the text object. If it doesn't find a view, it will fail to display, load and run the script.
So, we need to specify which view we want to use. The default view for OT script objects is the "OTScriptObjectView". With this view, you don't have to worry about seeing the script in the screen; it will be "invisible".
To specify the view to be used, add this view entry to the views section of the OTViewBundle in the otml:

<OTViewEntry
  objectClass="org.concord.otrunk.script.ui.OTScriptObject"
  viewClass="org.concord.otrunk.script.ui.OTScriptObjectView"/>

Now the script will run when the document is displayed!

Adding necessary imports and engine entries

We cannot forget another step: in order to specify that we want to use the scripting engine included in OTrunk, we need to add an OT engine bundle to the OTSystem bundles. Since we're using JavaScript, we need to add this snippet to the bundles section of the OTSystem section:

<OTScriptEngineBundle>
  <engines>
    <OTScriptEngineEntry 
      objectClass="org.concord.otrunk.script.js.OTJavascript"
      engineClass="org.concord.otrunk.script.js.OTJavascriptEngine"/>
  </engines>
</OTScriptEngineBundle>

We're almost ready to write the actual JavaScript. But before we can run the otml file, we need to add the necessary imports for all the new script objects we used:

<import class="org.concord.otrunk.script.ui.OTScriptObject"/>
<import class="org.concord.otrunk.script.ui.OTScriptVariable"/>
<import class="org.concord.otrunk.script.js.OTJavascript" />
<import class="org.concord.otrunk.script.OTScriptEngineBundle"/>
<import class="org.concord.otrunk.script.OTScriptEngineEntry"/>

Editing the script

Ok, finally! Up to this point, the otml can be loaded and run with the OTViewer. But the script won't do anything, since it's empty. So, we can now add our actual script, which will just set the text into our OTText object.
Replace the comment "//Here is where I will write my script" with this:

function init()
{
  //This function is called when the script is loaded.
  myTextVariable.setText("Hello world, I'm a script!!");
}

In this example, the script is accessing an OTText object directly, so it's using the setText() method on it.

Running the otml file with the script in it

That's it! Your otml is ready to be loaded and your script to be run. Just make sure that when you run your application, you add the jar files necessary for the JavaScript engine to your classpath. In case you need to manually add them, the jar files are located in the thirdparty project in cvs. For JavaScript, the files needed are: bsf-2.4.0.jar, js-1.6R5.jar and commons-logging.jar.

Running and looking at the full example online

You can download the otml file from svn at otrunk-examples/Script/script_basic_example.otml.

Look at the full example here

Run the full example here

Moving the script to an external file

Like it was mentioned before, it is recommended to write the script into a separate file. If it's JavaScript, you might want to give it the standard .js extension.

To specify that your script is in an external file, the OTScriptObject will look like this:

<OTScriptObject local_id="script_object">
  <variables>
    <OTScriptVariable name="myTextVariable" reference="${text_object}"/>
  </variables>
  <script>
    <OTJavascript src="script_basic_example.js"  />
  </script>
</OTScriptObject>
Document generated by Confluence on Jan 27, 2014 16:52